use Test::More;
use strict;
use warnings;
use Bio::Perl;
use Bio::Tools::Mlst;
use Data::Dumper;

my $database='neisseria'; # pubmlst
my $database2='spneumoniae'; # mlst.net
my $site='pubmlst'; # either pubmlst, mlstnet, ucc
my $site2='mlstnet'; 
my $adk_4=Bio::Seq->new(
  -seq=>'GAAGCGAAAAAAATCATTGACGAAGGCGGCTTGGTGCGCGACGACATCATTATCGGCATGGTCAAAGAACGCATCGCGCAAGACGACTGCAAAAACGGTTTCCTGTTCGACGGTTTCCCGCGCACATTGGCACAAGCCGAAGCGATGGTTGAAGCAGGCGTGGATTTGGATGCAGTCGTTGAAATCGATGTGCCTGACAGCGTGATTGTCGATCGTATGAGCGGCCGCCGCGTGCATTTGGCTTCCGGCCGTACTTACCACGTTACCTACAACCCGCCCAAAGTTGAAGGCAAAGACGACGTAACCGGCGAAGATTTGATTCAGCGCGACGACGACAAAGAAGAAACCGTGAAAAAACGCCTTGCCGTTTACCACGAGCAAACCGAAGTTTTGGTCGATTTTTACAGCAAACTGGAAGGCGAACACGCGCCTAAATACATCAAAGTTGACGGCACTCAGCCGGTA', # adk_-4
  -id=>"adk_4",
);
my $locus='adk_';
my $locus4='aroe';
my $match=6; # match on this many loci for an ST
my $allele=4;
my @st=(0,1,2,3,4,5,6,7,8,9,10,11); # $st[0] will be an error value
my $st1profile={abcZ=>1,adk_=>3,aroE=>1,fumC=>1,gdh_=>1,pdhC=>1,pgm_=>3};
my $st11profile={abcZ=>2,adk_=>3,aroE=>4,fumC=>3,gdh_=>8,pdhC=>4,pgm_=>6};
my $exactMatch='true'; # 'true' or 'false'
# declare examples' variables here
my ($pubmlst,$mlstnet,$seq,$count,$URL,$CC,$length,$blastresult);
my (@allele,@CC,@db,@field,@locusList,@isolate,@profile,@ST);
my (%profile,%result);
my $seqout=Bio::SeqIO->new(-format=>'fasta');

## preparation for the tests
# find the operating system
my $OS=$^O or warn("Warning: cannot determine your OS.");
if ($OS=~/Win/i) {
    $OS = 'windows';
} elsif ($OS=~/vms/i) {
    $OS = 'VMS';
} elsif ($OS=~/Mac/i) {
    $OS = 'mac';
} elsif ($OS=~/os2/i) {
    $OS = 'OS2';
} else {
    $OS = 'UNIX';
}

## start actual tests here
my $numTests=0; # increment as we go

# PUBMLST
$pubmlst=Bio::Tools::Mlst->new({database=>$database,locus=>$locus});
$numTests++; # increment right before a test in case it crashes
subtest "Constructor (Bio::Tools::Mlst->new)"=>sub{
  plan tests=>2;
  isa_ok($pubmlst,"Bio::Tools::Mlst","PubMLST");
  isa_ok($pubmlst,"Bio::Tools::Mlst::PubMLST","PubMLST");
};

$numTests++;
$seq=$pubmlst->getAllele({allele=>$allele}); 
ok($seq->seq eq $adk_4->seq, "getAllele");

$numTests++;
$blastresult=$pubmlst->blast({seq=>$adk_4,numresults=>1});
while( my $result = $blastresult->next_result ) {
  ## $result is a Bio::Search::Result::ResultI compliant object
  while( my $hit = $result->next_hit ) {
    ## $hit is a Bio::Search::Hit::HitI compliant object
    while( my $hsp = $hit->next_hsp ) {
      ## $hsp is a Bio::Search::HSP::HSPI compliant object
      ok($hsp->percent_identity == 100 && $hsp->length('total')==$adk_4->length,"BLAST");
    }  
  }
}

# This test will have to be periodically updated, I think.
# Current count: 326 (Feb 17, 2010)
$numTests++;
$count=$pubmlst->getAlleleCount();
ok($count>325,"getAlleleCount");

$numTests++;
print "Warning: the next test getAlleles might time out.\n";
@allele=$pubmlst->getAlleles();
ok($allele[3]->seq eq $adk_4->seq,"getAlleles");

if($OS ne "windows"){ # this test doesn't work on windows for some reason...?
  $numTests++;
  $URL=$pubmlst->getAlleleSequencesURL();
  ok($URL eq 
          "http://pubmlst.org/cgi-bin/bigsdb/bigsdb.pl?db=pubmlst_neisseria_seqdef&page=downloadAlleles&locus=abcZ"
        ||"http://pubmlst.org/perl/bigsdb/bigsdb.pl?db=pubmlst_neisseria_seqdef&page=downloadAlleles&locus=abcZ"
    ,"getAlleleSequencesURL");
}

$numTests++;
$CC=$pubmlst->getClonalComplex({ST=>$st[11]}); 
like($CC,qr/11/,"getClonalComplex");

# This test's outcome could possibly change (not likely).
# It checks for CC-4821
$numTests++;
@CC=$pubmlst->getClonalComplexes();
@CC=grep(/4821/,@CC);
ok(scalar @CC>0,"getClonalComplexes");

# See if Neisseria is in the list
$numTests++;
@db=$pubmlst->getDatabaseList();
my $getDatabaseListWorks=0; # getDatabaseList doesn't work by default
for(my $i=0;$i<@db;$i++){
  if($db[$i]{name}=~/neisseria/i){
    $getDatabaseListWorks=1;
    last;
  }
}
ok($getDatabaseListWorks,"getDatabaseList");

# current isolate count as of Feb 18 is 14663
$numTests++;
$count=$pubmlst->getIsolateCount(); 
ok($count>14662,"getIsolateCount");

$numTests++;
subtest "Get forward and reverse consensus sequences"=>sub{
  plan tests=>2;
  # The adk_ forward consensus as of Feb 18 2010 is "GARGCRAAAAAAAWYATYGA"
  $seq=$pubmlst->getForwardConsensus();
  ok($seq->seq eq "GARGCRAAAAAAAWYATYGA","getForwardConsensus");

  # "TYGAYGGHACYCRRSHRGTR"
  $seq=$pubmlst->getReverseConsensus();
  ok($seq->seq eq "TYGAYGGHACYCRRSHDGTR","getReverseConsensus ".$seq->seq);
};

$numTests++;
@field=$pubmlst->getIsolateFields();
# test on a few different fields
subtest "getIsolateFields"=>sub{
  my $numTests=3;
  plan tests=>$numTests;
  my $glue="~~";
  foreach my $hash (@field){
  	my $succinctLine=join($glue,($$hash{name},$$hash{description},$$hash{type}));
    if($succinctLine eq join($glue,("id","primary key","integer"))){
      pass("Id field found!");
    }
    if($succinctLine eq join($glue,("isolate","isolate name","text"))){
      pass("Isolate field found!");
    }
    if($succinctLine eq join($glue,("year","year of isolation","integer"))){
      pass("Year field found!");
    }
  }
};

$numTests++;
@locusList=$pubmlst->getLocusList();
ok("abcZ" eq $locusList[0],"getLocusList");

# this should include more loci, as others are added with a variable length
$numTests++;
subtest "getLocusLength"=>sub{
  plan tests=>1;
  $length=$pubmlst->getLocusLength({locus=>$locus});
  ok($length==465,"$locus");
};

$numTests++;
%profile=$pubmlst->getProfile({ST=>$st[11]});
my $getProfileTestResult=join(" ",$profile{ST},$profile{CC},$profile{'fumC'},$profile{'abcZ'});
subtest "getProfile"=>sub{
  plan tests=>4;
  ok($profile{ST}==11,"ST");
  like($profile{CC},qr/11/,"CC");
  ok($profile{fumC}==3,"fumC (One locus)");
  ok($profile{abcZ}==2,"abcZ (Another locus)");
};

# 8015 STs as of Feb 18
$numTests++;
$count=$pubmlst->getProfileCount(); 
ok($count>8014,"getProfileCount");

if($OS ne "windows"){
  $numTests++;
  $URL=$pubmlst->getProfileListURL();
  ok("http://pubmlst.org/cgi-bin/bigsdb/bigsdb.pl?db=pubmlst_neisseria_seqdef&page=downloadProfiles&scheme_id=1" 
    eq $URL, "getProfileListURL")
}

# one ST-1 isolate's ID is 11378 (Feb 19, 2010)
$numTests++;
@isolate=$pubmlst->getRelatedIsolateIdsByProfile({profile=>$st1profile,match=>7});
@isolate=grep(/^11378$/,@isolate);
ok(@isolate>0,"getRelatedIsolateIdsByProfile");

$numTests++;
@isolate=$pubmlst->getRelatedIsolateIdsByST({ST=>$st[1],match=>7});
@isolate=grep(/^11378$/,@isolate);
ok(@isolate>0,"getRelatedIsolateIdsByST");

# test a few different fields in the profile
$numTests++;
@profile=$pubmlst->getRelatedProfilesByProfile({profile=>$st1profile,match=>7});
%profile=%{$profile[0]};
subtest "getRelatedProfilesByProfile"=>sub{
  plan tests=>3;
  ok(1==$profile{ST},"ST");
  ok(1==$profile{pdhC},"pdhC (one locus)");
  ok(3==$profile{adk}||3==$profile{adk_},"adk_ (a second locus)");
};

$numTests++;
@profile=$pubmlst->getRelatedProfilesByST({ST=>$st[1],match=>7});
%profile=%{$profile[0]};
subtest "getRelatedProfilesByST"=>sub{
  plan tests=>3;
  ok(1==$profile{ST},"ST");
  ok(1==$profile{pdhC},"pdhC (one locus)");
  ok(3==$profile{adk}||3==$profile{adk_},"adk_ (a second locus)");
};

$numTests++;
@ST=$pubmlst->getRelatedSTsByProfile({profile=>$st11profile,match=>$match});
ok(11==$ST[0],"getRelatedSTsByProfile");

$numTests++;
@ST=$pubmlst->getRelatedSTsByST({ST=>$st[10],match=>7});
ok(10==$ST[0],"getRelatedSTsByST");

$numTests++;
@ST=$pubmlst->getSTsByAlleles({profile=>$st11profile});
ok(11==$ST[0],"getSTsByAlleles");

# one ID from USA is 14489
$numTests++;
@isolate=$pubmlst->isolateQuery({fields=>{country=>"USA"},exactMatch=>$exactMatch});
@isolate=grep(/^14489$/,@isolate);
ok(@isolate>0,"isolateQuery");

$numTests++;
$blastresult=$pubmlst->locusBlast({seq=>$adk_4,locus=>"adk_",numresults=>1});
while( my $result = $blastresult->next_result ) {
  ## $result is a Bio::Search::Result::ResultI compliant object
  while( my $hit = $result->next_hit ) {
    ## $hit is a Bio::Search::Hit::HitI compliant object
    while( my $hsp = $hit->next_hsp ) {
      ## $hsp is a Bio::Search::HSP::HSPI compliant object
      ok($hsp->percent_identity == 100 && $hsp->length('total')==$adk_4->length,"locusBlast");
    }  
  }
}

$numTests++;
%result=$pubmlst->locusQuery({seq=>$adk_4,locus=>"adk_"});
my @resultKey=keys (%result);
is_deeply(\@resultKey,['diffs','result'],"locusQuery");

# Wrap up the test.
plan tests=>$numTests;
done_testing($numTests);
exit;
# MLSTNET
$mlstnet=Bio::Tools::Mlst->new({repository=>$site2,database=>$database2,locus=>$locus4});
#@blastHit=$mlstnet->blast({sequence=>$sequence4,numresults=>3});print Dumper @blastHit;

$URL=$mlstnet->getProfileListURL(); print "$URL\n";

$count=$mlstnet->getProfileCount; print "$count\n";

%profile=$mlstnet->getProfile({ST=>4292}); print Dumper %profile;

#$seq=$mlstnet->getAllele({locus=>$locus4,allele=>$allele}); $seqout->write_seq($seq);
print $mlstnet->getAlleleCount();

exit; 
